package com.iot08.api.service;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.iot08.api.constant.Constant;
import com.iot08.api.utils.wxpay.WxPayUtil;
import com.iot08.common.entity.app.WechatPayNotifyInfo;
import com.iot08.common.service.base.BaseService;
import com.iot08.common.utils.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.util.Date;

/**
 * @author cwj
 * @description
 * @date 2025/1/4 14:26
 **/
@Slf4j
@Service
public class WechatPayNotifyInfoService extends BaseService<WechatPayNotifyInfo> {

    @Resource
    private WxPayUtil wxPayUtil;


    /**
     * @description 设置微信支付异步通知的信息
     * @author cwj
     * @param [body, objectMapper]
     * @return com.iot08.common.entity.app.WechatPayNotifyInfo
     * @date @time 2025/1/4 14:10
     **/
    public WechatPayNotifyInfo settingWechatPayNotifyInfo(String requestBody,String notifyType) throws Exception {
        //检查通知结果
        ObjectMapper objectMapper = new ObjectMapper();
        JSONObject body = objectMapper.readValue(requestBody,JSONObject.class);
        WechatPayNotifyInfo wechatPayNotifyInfo = new WechatPayNotifyInfo();
        wechatPayNotifyInfo.setNotifyId(body.getString("id"));
        //转转时间格式字符串
        wechatPayNotifyInfo.setNotifyCreateTime(DateUtil.rfc3339FormatDateStr(body.getString("create_time"),DateUtil.FORMAT_1));
        wechatPayNotifyInfo.setSummary(body.getString("summary"));
        wechatPayNotifyInfo.setResourceType(body.getString("resource_type"));
        wechatPayNotifyInfo.setEventType(body.getString("event_type"));
        JSONObject resource = body.getJSONObject("resource");
        wechatPayNotifyInfo.setOriginalType(body.getString("original_type"));
        wechatPayNotifyInfo.setAlgorithm(body.getString("algorithm"));
        if(StringUtils.isNotEmpty(resource.getString("associated_data"))){
            wechatPayNotifyInfo.setAssociatedData(resource.getString("associated_data"));
        }
        wechatPayNotifyInfo.setNonce(resource.getString("nonce"));
        wechatPayNotifyInfo.setCiphertext(resource.getString("ciphertext"));
        log.info("解密参数：{}，{}，{}",wechatPayNotifyInfo.getAssociatedData(),wechatPayNotifyInfo.getNonce(),wechatPayNotifyInfo.getCiphertext());
        //解密加密内容
        String decryptedData = wxPayUtil.decryptResource(wechatPayNotifyInfo.getAssociatedData(),wechatPayNotifyInfo.getNonce(),wechatPayNotifyInfo.getCiphertext());
        log.info("解密后的数据：" + decryptedData);
        //保存微信支付通知信息
        JSONObject notifyInfo = objectMapper.readValue(decryptedData,JSONObject.class);
        wechatPayNotifyInfo.setTransactionId(notifyInfo.getString("transaction_id")); 
        JSONObject amount = notifyInfo.getJSONObject("amount");
        //单位为分,订单总金额，单位为分
        wechatPayNotifyInfo.setPayerTotal(amount.getBigDecimal("payer_total").divide(new BigDecimal(100),2, RoundingMode.DOWN));
        wechatPayNotifyInfo.setTotal(amount.getBigDecimal("total").divide(new BigDecimal(100),2,RoundingMode.DOWN));
        //货币类型
        if(StringUtils.isNotEmpty(amount.getString("currency"))) {
            //货币类型
            wechatPayNotifyInfo.setCurrency(amount.getString("currency"));
        }
        if(StringUtils.isNotEmpty(amount.getString("payer_currency"))) {
            //支付货币类型
            wechatPayNotifyInfo.setPayerCorrency(amount.getString("payer_currency"));
        }
        if(StringUtils.isNotEmpty(amount.getString("refund"))) {
            wechatPayNotifyInfo.setRefund(amount.getBigDecimal("refund").divide(new BigDecimal(100),2, RoundingMode.DOWN));
        }
        if(StringUtils.isNotEmpty(amount.getString("payer_refund"))) {
            wechatPayNotifyInfo.setPayerRefund(amount.getBigDecimal("payer_refund").divide(new BigDecimal(100),2, RoundingMode.DOWN));
        }
        wechatPayNotifyInfo.setOutTradeNo(notifyInfo.getString("out_trade_no"));
        if(Constant.WECHAT_PAYMENT_NOTIFY_TYPE.equals(notifyType)) {
            wechatPayNotifyInfo.setTradeStateDesc(notifyInfo.getString("trade_state_desc"));
            wechatPayNotifyInfo.setTradeType(notifyInfo.getString("trade_type"));
            wechatPayNotifyInfo.setTradeStatus(notifyInfo.getString("trade_state"));
            wechatPayNotifyInfo.setAppid(notifyInfo.getString("appid"));
            wechatPayNotifyInfo.setBankType(notifyInfo.getString("bank_type"));
        } else {
            wechatPayNotifyInfo.setRefundNo(notifyInfo.getString("refund_id"));
            wechatPayNotifyInfo.setOutRefundNo(notifyInfo.getString("out_refund_no"));
            wechatPayNotifyInfo.setTradeStatus(notifyInfo.getString("refund_status"));
            wechatPayNotifyInfo.setUserReceivedAccount(notifyInfo.getString("user_received_account"));
        }
        wechatPayNotifyInfo.setMchid(notifyInfo.getString("mchid"));
        //转换时间格式字符串
        wechatPayNotifyInfo.setSuccessTime(DateUtil.rfc3339FormatDateStr(notifyInfo.getString("success_time"),DateUtil.FORMAT_1));
        wechatPayNotifyInfo.setCreateDate(new Date());
        wechatPayNotifyInfo.setUpdateDate(new Date());
        return wechatPayNotifyInfo;
    }
    
    
    /**
     * @description 保存或更新微信支付通知记录
     * @author cwj
     * @param [requestBody]
     * @return com.iot08.common.entity.app.WechatPayNotifyInfo
     * @date @time 2025/1/4 15:01
     **/
    public JSONObject saveOrUpdateNotifyInfo(String requestBody,String notifyType) throws Exception {
        JSONObject jsonObject = new JSONObject();
        boolean beforeHasReceived = false;
        //设置微信支付通知的信息
        WechatPayNotifyInfo wechatPayNotifyInfo = settingWechatPayNotifyInfo(requestBody,notifyType);
        if(!StringUtils.isEmpty(wechatPayNotifyInfo.getEventType())) {
            notifyType = wechatPayNotifyInfo.getEventType().split("\\.")[0];
        }
        //查询通知记录是否存在（支付通知/退款通知）
        WechatPayNotifyInfo wpn = queryWechatPayNotifyInfoByOutTradeNo(wechatPayNotifyInfo.getOutTradeNo(),notifyType);
        if(ObjectUtils.isEmpty(wpn)){
            this.save(wechatPayNotifyInfo);
        } else {
            if("SUCCESS".equals(wpn.getTradeStatus())) {
                beforeHasReceived = true;
            }
            Update update = setWechatPayNotifyInfoUpdate(wechatPayNotifyInfo,notifyType);
            this.updateById(new ObjectId(wpn.getId()),update);
        }
        jsonObject.put("wechatPayNotifyInfo",wechatPayNotifyInfo);
        jsonObject.put("beforeHasReceived",beforeHasReceived);
        return jsonObject;
    }

    /**
     * @description 根据订单号查询通知信息
     * @author cwj
     * @param [outTradeNo]
     * @return com.iot08.common.entity.app.WechatPayNotifyInfo
     * @date @time 2025/1/7 11:56
     **/
    public WechatPayNotifyInfo queryWechatPayNotifyInfoByOutTradeNo(String outTradeNo,String notifyType) {
        // "i"表示大小写不敏感，按照支付通知/退款通知等不同类型来查询通知记录
        Query query = new Query(Criteria.where("outTradeNo").is(outTradeNo).and("eventType").regex(notifyType,"i")).limit(1);
        //查询通知记录
        return this.findOne(query);
    }

    /**
     * @description 更新微信支付通知信息
     * @author cwj
     * @param [wechatPayNotifyInfo]
     * @return org.springframework.data.mongodb.core.query.Update
     * @date @time 2025/1/4 15:08
     **/
    public Update setWechatPayNotifyInfoUpdate(WechatPayNotifyInfo wechatPayNotifyInfo,String notifyType){
        Update update = new Update();
        update.set("notifyId",wechatPayNotifyInfo.getNotifyId());
        update.set("notifyCreateTime",wechatPayNotifyInfo.getNotifyCreateTime());
        update.set("summary",wechatPayNotifyInfo.getSummary());
        update.set("resourceType",wechatPayNotifyInfo.getResourceType());
        update.set("eventType",wechatPayNotifyInfo.getEventType());
        update.set("originalType",wechatPayNotifyInfo.getOriginalType());
        update.set("algorithm",wechatPayNotifyInfo.getAlgorithm());
        if(ObjectUtils.isNotEmpty(wechatPayNotifyInfo.getAssociatedData())){
            update.set("associatedData",wechatPayNotifyInfo.getAssociatedData());
        }
        update.set("nonce",wechatPayNotifyInfo.getNonce());
        update.set("ciphertext",wechatPayNotifyInfo.getCiphertext());
        update.set("transactionId",wechatPayNotifyInfo.getTransactionId());
        update.set("payerTotal",wechatPayNotifyInfo.getPayerTotal());
        update.set("total",wechatPayNotifyInfo.getTotal());
        update.set("outTradeNo",wechatPayNotifyInfo.getOutTradeNo());
        if(Constant.WECHAT_PAYMENT_NOTIFY_TYPE.equals(notifyType)){
            update.set("currency",wechatPayNotifyInfo.getCurrency());
            update.set("payerCorrency",wechatPayNotifyInfo.getPayerCorrency());
            update.set("tradeStateDesc",wechatPayNotifyInfo.getTradeStateDesc());
            update.set("tradeType",wechatPayNotifyInfo.getTradeType());
            update.set("appid",wechatPayNotifyInfo.getAppid());
            update.set("bankType",wechatPayNotifyInfo.getBankType());
        } else {
            update.set("refundNo",wechatPayNotifyInfo.getRefundNo());
            update.set("outRefundNo",wechatPayNotifyInfo.getOutRefundNo());
            update.set("userReceivedAccount",wechatPayNotifyInfo.getUserReceivedAccount());
        }
        update.set("tradeStatus",wechatPayNotifyInfo.getTradeStatus());
        update.set("mchid",wechatPayNotifyInfo.getMchid());
        update.set("successTime",wechatPayNotifyInfo.getSuccessTime());
        update.set("updateTime",new Date());
        return update;
    }

}
